/** @file

Copyright (c) 2006-2023, Kunlun BIOS, Kunlun Technology (Beijing) Co., Ltd.. All
Rights Reserved.

You may not reproduce, distribute, publish, display, perform, modify, adapt,
transmit, broadcast, present, recite, release, license or otherwise exploit
any part of this publication in any form, by any means, without the prior
written permission of Kunlun Technology (Beijing) Co., Ltd..

Module Name:

  SetupUtilityApp.c

Abstract:


Revision History:


**/
#include <Library/DebugLib.h>
#include <Library/DynamicFormSupportLib.h>
#include <Protocol/SetupHiiDataMgr.h>
//startk-klk-alt-P000A-add//
//#include <Protocol/KlHiiPopup.h>
//end-klk-alt-P000A-add//
//add-klk-lyang-P000A-start//
//add-klk-lyang-P000A-end//

#include "SetupUtilityApp.h"
#include "SetupConfig.h"
//[jckuang-0020]
#include <Pi/PiStatusCode.h>
#include <Library/PostCodeLib.h>
#include <Library/ReportStatusCodeLib.h>
#include "PostCode.h"
//[jckuang-0020]
EFI_HII_DATABASE_PROTOCOL           *mHiiDatabase;
EFI_GUID   mFormAdvanceGuid = FORMSET_ID_GUID_ADVANCE;
EFI_GUID   mFormSecurityGuid = FORMSET_ID_GUID_SECURITY;

EFI_GUID   mFormSetGuid      = SETUP_FORMSET_GUID;


/**
  Brief description of FindHiiHandleFromFormGuid.

  @param  FormGuid

**/
EFI_HII_HANDLE
FindHiiHandleFromFormGuid (
  EFI_GUID*          FormGuid
)
{
  UINT8                Index;

  if (!CheckSetupHiiDataManager ()) {
    return NULL;
  }

  for (Index = 0;Index < gSetupDataManagment->MenuItemCount;Index++) {
    if (CompareGuid(FormGuid, gSetupDataManagment->MenuList[Index].FormSetGuid)) {
      return gSetupDataManagment->MenuList[Index].Page;
    }
  }
  return NULL;
}

/**
 Display Setup Utility.

 @param[in] HiiHandle             Pointer to HII handle list
 @param[in] HiiHandleCount        The number of HII handle list

 @retval EFI_SUCCESS              Success to display Setup Utility
 @retval Other                    Fail to locate form browser protocol or send form
**/
EFI_STATUS
DisplaySetupUtility (
  VOID
  )
{
  EFI_STATUS                                Status;
  EFI_FORM_BROWSER2_PROTOCOL                *FormBrowser2;
  EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL    *FormBrowserEx2;
  EFI_BROWSER_ACTION_REQUEST                ActionRequest;
  EFI_GUID                                  ZeroGuid;
  EFI_HII_HANDLE                            DispPage;
  BOOLEAN                                   Continue;

  Continue = TRUE;

  Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  if (!CheckSetupHiiDataManager ()) {
    return EFI_UNSUPPORTED;
  }
  //gST->ConOut->OutputString (gST->ConOut,L"Enter Setup Utility\n");

  gSetupDataManagment->AtRoot          = TRUE;
  gSetupDataManagment->CurRoot         = gSetupDataManagment->MenuItemCount - 1;
  gSetupDataManagment->UseMenus        = TRUE;
  gSetupDataManagment->Direction       = NoChange;
  gSetupDataManagment->Finished        = FALSE;
  gSetupDataManagment->Firstin         = TRUE;
  gSetupDataManagment->LayoutIsChanged = FALSE;
  gSetupDataManagment->RepaintFrameLine= TRUE;

  DispPage = gSetupDataManagment->MenuList[gSetupDataManagment->MenuItemCount - 1].Page;

  DEBUG ((EFI_D_ERROR, "Setup Utility Display\n"));
  //
  // Loop until exit condition is found.  Use direction indicators and
  // the menu list to determine what root page needs to be displayed.
  //
  //gBS->RestoreTPL (TPL_APPLICATION);
  while (Continue) {
    ZeroMem (&ZeroGuid, sizeof (EFI_GUID));
    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
  //gST->ConOut->OutputString (gST->ConOut,gSetupDataManagment->MenuList[gSetupDataManagment->CurRoot].String);
    //DEBUG ((EFI_D_ERROR, "Setup Utility Display %s\n",gSetupDataManagment->MenuList[gSetupDataManagment->CurRoot].String));

    Status = FormBrowser2->SendForm (
                             FormBrowser2,
                             (EFI_HII_HANDLE *) &DispPage, // The HII Handle
                             1,
                             &ZeroGuid,//&mFormSetGuid,//&ZeroGuid,
                             0,
                             NULL,
                             &ActionRequest
                             );
    //DEBUG ((EFI_D_ERROR, "Next Page\n"));
    // Check whether user change any option setting which needs a reset to be effective
    //

    //
    // Force return to Device Manager or Exit if finished
    //

    gSetupDataManagment->AtRoot  = TRUE;
    gSetupDataManagment->Firstin = FALSE;
    if (gSetupDataManagment->Finished) {
      //
      // Need to set an exit at this point
      //
      gSetupDataManagment->UseMenus = FALSE;
      Continue = FALSE;
      break;
    }
    //
    // Check for next page or exit states
    //
    switch (gSetupDataManagment->Direction) {

    case Right:
      //
      // Update Current Root Index
      //
      if (gSetupDataManagment->CurRoot == 0) {
        gSetupDataManagment->CurRoot = gSetupDataManagment->MenuItemCount - 1;
      } else {
        gSetupDataManagment->CurRoot--;
      }
      //
      // Set page to display
      //
      DispPage = gSetupDataManagment->MenuList[gSetupDataManagment->CurRoot].Page;

      //
      // Update Direction Flag
      //
      gSetupDataManagment->Direction = NoChange;
      ////DEBUG ((EFI_D_ERROR, "Setup DISPLAY page %s\n",gSetupDataManagment->MenuList[gSetupDataManagment->CurRoot].String));
      break;
    case Left:
      //
      // Update Current Root Index
      //
      if (gSetupDataManagment->CurRoot == gSetupDataManagment->MenuItemCount - 1) {
        gSetupDataManagment->CurRoot = 0;
      } else {
        gSetupDataManagment->CurRoot++;
      }

      //
      // Set page to display
      //
      DispPage = gSetupDataManagment->MenuList[gSetupDataManagment->CurRoot].Page;

      //
      // Update Direction Flag
      //
      gSetupDataManagment->Direction = NoChange;
      break;
    case Jump:
      // Update Current Root Index
      if ((gSetupDataManagment->CurRoot >= 0) &&
          (gSetupDataManagment->CurRoot <= gSetupDataManagment->MenuItemCount - 1)) {
        //
        // Set page to display
        //
        DispPage = gSetupDataManagment->MenuList[gSetupDataManagment->CurRoot].Page;
      }

      //
      //Repaint Menu and help prompt
      //
      gSetupDataManagment->Firstin = TRUE;

      //
      // Update Direction Flag
      //
      gSetupDataManagment->Direction = NoChange;
      break;
    default:
      if (FormBrowserEx2->IsResetRequired()) {
        gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
      }
      gSetupDataManagment->UseMenus = FALSE;
      Continue = FALSE;
      break;
    }

  }
  //gST->ConOut->SetAttribute (gST->ConOut, EFI_BLACK | EFI_BACKGROUND_BLACK);
//add-klk-lyang-P000A-start//
  gST->ConOut->ClearScreen (gST->ConOut);
//add-klk-lyang-P000A-end//

  return Status;
}

/**
 Display Setup Utility to allow user to configure the platform.

  This is an application.
  Step1 to find all formset handdles that need to display
  Step2 Install gSetupUtilityApplicaion protocol to notify SetupHiiData driver to put hii data to hii database.
  Step3 call sendform to send the formsets.
  Write by TANG

  @param  ImageHandle
  @param  SystemTable

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
EFIAPI
SetupUtilityAppMain (
  IN EFI_HANDLE                  ImageHandle,
  IN EFI_SYSTEM_TABLE            *SystemTable
  )
{
  EFI_STATUS                               Status;
  // EFI_HII_HANDLE                           *HiiHandle;
  // UINTN                                    HiiHandleCount;
  EFI_SETUP_UTILITY_APPLICATION_PROTOCOL   *SetupUtilityApp;
  EFI_HANDLE                               SetupUtilityHandle;
  EFI_HII_HANDLE                           AdvancedHiiHandle;
  EFI_HII_HANDLE                           SecurityHiiHandle;
  EFI_INPUT_KEY                            Key;

//add-klk-lyang-P000A-start//
  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
  // SetupSetConsoleMode();//lyang move to setuphiidata

  //gST->ConOut->OutputString (gST->ConOut,L"enter setup app\n");
  Status = gBS->LocateProtocol (&gEfiSetupUtilityApplicationProtocolGuid, NULL, (VOID **) &SetupUtilityApp);
  if (!EFI_ERROR (Status)) {
    return EFI_ACCESS_DENIED;
  }

  Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &mHiiDatabase);
  if (EFI_ERROR (Status)) {
    gST->ConOut->OutputString (gST->ConOut,L"NO hii interface\n");
    return Status;
  }

  SetupUtilityApp = AllocatePool (sizeof(EFI_SETUP_UTILITY_APPLICATION_PROTOCOL));
  if (SetupUtilityApp == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  //[jckuang-0020]
  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, BDS_SETUP_START);//[gliu-0062]
  //[jckuang-0020]
  SetupUtilityHandle = 0;
  SetupUtilityApp->VfrDriverState = InitializeSetupUtility;
  Status = gBS->InstallProtocolInterface (
                  &SetupUtilityHandle,
                  &gEfiSetupUtilityApplicationProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  SetupUtilityApp
                  );
  if (!EFI_ERROR (Status)) {
  //
  // Install setup utility application protocol to trigger VFR driver to install HII package
  //

    //gST->ConOut->OutputString (gST->ConOut,L"Prepare to display SetupUtility\n");
    //[gliu-0023]
    gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
    //[gliu-0023]
    AdvancedHiiHandle = FindHiiHandleFromFormGuid(&gFormsetIdGuidAdvance);
    SecurityHiiHandle = FindHiiHandleFromFormGuid(&gFormsetIdGuidSecurity);

    // AdvancedHiiHandle = (EFI_HII_HANDLE)gSetupDataManagment->MenuList[gSetupDataManagment->MenuItemCount - 2].Page;
    // SecurityHiiHandle = (EFI_HII_HANDLE)gSetupDataManagment->MenuList[gSetupDataManagment->MenuItemCount - 3].Page;
    //
    // Update Dynamic menus.
    //
    if (AdvancedHiiHandle) {
      UpdateSetupDynamicForm(
        AdvancedHiiHandle,
        &gEfiHiiPlatformSetupFormsetGuid,
        &gFormsetIdGuidAdvance,
        ROOT_FORM_ID,
        LABEL_THIRD_PARTY_DRIVER_INFORMATION
        );
    }
    if (SecurityHiiHandle) {
      UpdateSetupDynamicForm(
        SecurityHiiHandle,
        (EFI_GUID*)PcdGetPtr (PcdSecurityLinkToFormsetGuid),
        &gFormsetIdGuidSecurity,
        ROOT_FORM_ID,
        LABEL_SECURITY_DRIVER
        );
    }
//add-klk-lyang-P000A-start//before enter setup,clear keyboard buffer
    do{
      Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    }while(Status != EFI_NOT_READY);
//add-klk-lyang-P000A-end//
    //[gliu-0025]add-start
    Status = EFI_SUCCESS;
    //[gliu-0025]add-end
    DisplaySetupUtility ();


    //
    // Re-install setup utility application protocol to trigger VFR driver to uninstall HII package
    //
    SetupUtilityApp->VfrDriverState = ShutdownSetupUtility;
    gBS->ReinstallProtocolInterface (
           SetupUtilityHandle,
           &gEfiSetupUtilityApplicationProtocolGuid,
           SetupUtilityApp,
           SetupUtilityApp
           );

    gBS->UninstallProtocolInterface (
           SetupUtilityHandle,
           &gEfiSetupUtilityApplicationProtocolGuid,
           SetupUtilityApp
           );
//remove-klk-lyang-P000A-start//
    //HiiRemovePackages (gStringPackHandle);
//remove-klk-lyang-P000A-end//
  }
  return Status;
}

